package org.jeecg.cn.edu.scau.vm.machineTime.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.cn.edu.scau.vm.common.consts.DefaultConst;
import org.jeecg.cn.edu.scau.vm.container.domain.VmContainerUsage;
import org.jeecg.cn.edu.scau.vm.container.service.VmContainerUsageService;
import org.jeecg.cn.edu.scau.vm.machineTime.entity.VmGroupSettings;
import org.jeecg.cn.edu.scau.vm.machineTime.entity.VmUserSettings;
import org.jeecg.cn.edu.scau.vm.machineTime.mapper.VmUserSettingsMapper;
import org.jeecg.cn.edu.scau.vm.machineTime.service.IVmGroupSettingsService;
import org.jeecg.cn.edu.scau.vm.machineTime.service.IVmUserSettingsService;
import org.jeecg.cn.edu.scau.vm.machineTime.vo.UserSettingsVo;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service("vmUserSettingsService")
public class VmUserSettingsServiceImpl
        extends ServiceImpl<VmUserSettingsMapper, VmUserSettings>
        implements IVmUserSettingsService {
    private static final Logger logger = LoggerFactory.getLogger(VmUserSettingsServiceImpl.class);
    @Resource
    private ISysUserService userService;
    @Resource
    private IVmGroupSettingsService vmGroupSettingsService;
    @Resource
    private VmContainerUsageService usageService;

    @Override
    public IPage<UserSettingsVo> pageInfo(Page<VmUserSettings> page, QueryWrapper<VmUserSettings> queryWrapper) {
        Page<VmUserSettings> rawPage = super.page(page, queryWrapper);
        // 封装新对象
        List<String> userIds = rawPage.getRecords().stream().map(VmUserSettings::getUserId).collect(Collectors.toList());
        // 获取缓存对象
        Map<String, VmContainerUsage> usageMap = usageService.getUsageByIds(userIds);
        // 渲染数据
        List<UserSettingsVo> userSettingsVoList = rawPage.getRecords().stream().map((settings) -> {
            UserSettingsVo settingsVo = new UserSettingsVo();
            BeanUtils.copyProperties(settings, settingsVo);
            settingsVo.setMonthGpuNumber(usageMap.get(settings.getUserId()).getRemainGpuCardNumber());
            settingsVo.setMonthMachineTime(usageMap.get(settings.getUserId()).getRemainIngTime());
            return settingsVo;
        }).collect(Collectors.toList());
        // 重新渲染对象
        Page<UserSettingsVo> newPage = new Page<>();
        BeanUtils.copyProperties(rawPage, newPage, "records");
        newPage.setRecords(userSettingsVoList);
        return newPage;
    }

    @Override
    public VmUserSettings getByUserId(String userId) {
        QueryWrapper<VmUserSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        return this.getOne(queryWrapper);
    }

    @Override
    public VmUserSettings createUserSetting(LoginUser loginUser) {
        // 1. 创建用户设置
        // 1.2 如果此用户没有分组 || 该分组下没有设置分组配额
        VmUserSettings vmUserSettings = new VmUserSettings();
        vmUserSettings.setGpuCardNum(DefaultConst.DEFAULT_GPU_CARD_NUMBER);
        vmUserSettings.setMachineTimeAllocate(DefaultConst.DEFAULT_MACHINE_TIME_PER_MONTH);
        // 2. 填充公共字段
        vmUserSettings.setCreateTime(LocalDateTime.now());
        vmUserSettings.setUpdateTime(LocalDateTime.now());
        vmUserSettings.setCreateBy(loginUser.getId());
        vmUserSettings.setUpdateBy(loginUser.getId());
        // 3. 执行插入
        this.save(vmUserSettings);
        logger.info("默认用户配置插入完毕:{}", vmUserSettings);
        return vmUserSettings;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 存在代理事务的问题
    public Result<String> syncData() {
        // 先调用分组配额的相关同步方法
        int count = vmGroupSettingsService.syncGroupData();
        logger.info("初始化了分组配额,共新增{}条数据", count);
        // 1. 同步数据结果
        int addCount;
        // 2. 获取用户和当前配额表中的差额用户数据
        // 2.1 获取当前用户配额表中的数据
        List<VmUserSettings> settingsList = this.list();
        // 2.2 组装ids
        List<String> ids = settingsList.stream().map(VmUserSettings::getUserId).collect(Collectors.toList());
        // 2.3 根据ids执行数据插入
        List<SysUser> toBeAddUserList;
        if (!ids.isEmpty()) {
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.notIn("id", ids);
            toBeAddUserList = userService.list(queryWrapper);
        } else {
            toBeAddUserList = userService.list();
        }
        // 2. 提取需要的数据,封装对象
        List<VmUserSettings> toBeAddSettingsList = toBeAddUserList.stream().map((user) -> {
            // 1. 查询用户对应的部门默认配额
            String orgCode = user.getOrgCode();
            VmGroupSettings groupSettings = vmGroupSettingsService.getByOrgCode(orgCode);
            if (Objects.isNull(groupSettings)) {
                // 执行分组配额创建
                groupSettings = vmGroupSettingsService.createGroupSettings(orgCode);
            }
            // 2. 填充相关数据
            return VmUserSettings.builder()
                    .userId(user.getId())
                    .userName(user.getUsername())
                    .machineTimeAllocate(groupSettings.getMachineTimeAllocate())
                    .gpuCardNum(groupSettings.getGpuCardNum())
                    .createBy("admin")
                    .updateBy("admin")
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
        }).collect(Collectors.toList());
        this.saveBatch(toBeAddSettingsList);
        addCount = toBeAddSettingsList.size();
        // 3. 返回结果
        String resultString = String.format("本次新增%s条数据", addCount);
        // 4. usage相关
        usageService.syncData();
        logger.info(resultString);
        return Result.ok("同步完成!" + resultString);
    }


}
